package network.ssl;


import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import network.messages.KrakenClientMsg;
import network.messages.KrakenServerMsg;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Restrictions;

import bdd.sql.server.hibernate.HibernateUtil;
import bdd.sql.server.bean.Keystore;
import bdd.sql.server.bean.ServerSite;
import bdd.sql.server.bean.Video;

import security.aes.AES256;
import security.authentification.Token;
import security.diffie.hellmann.CipherModule;
import security.diffie.hellmann.DiffieHellman;
import tools.AppletConstant;
import tools.ConfParser;
import tools.ExecuteExternalApplication;
import tools.FileUtils;
import tools.KeyParser;
import tools.StringUtils;
import tools.math.Math_;

/**
 * Traite les commandes reçues par le serveur.
 * @author Guillaume Poças & Jean-François Augé
 */
public class KrakenSSLCommandInterpreter {
	
	private KrakenSSLThread krakenThread;
	private String savedMessage;
	private KrakenSSLThreadSendImage threadSendImage;
	private String camName;
	private String numDemande;
	private String listVideos;
	private String userName;
	
	private DiffieHellman dh;
	
	/**
	 * Constructeur.
	 * @param thread
	 */
	public KrakenSSLCommandInterpreter(KrakenSSLThread thread){
		this.krakenThread = thread;
		this.savedMessage = "";
		this.camName = "";
		this.numDemande = "";
	}
	
	/**
	 * Interprete la commande.
	 * @param msg
	 */
	public void interpret(String msg){
		String[] msgCmd;
		@SuppressWarnings("unused")
		String[] testSavedMessage;
		
		System.out.println("KrakenCommandInterpreter: J'analyse : \""+msg+"\"");
		
		msgCmd = msg.split("  ");
		
		//Identification Client-Serveur
		if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.KRAKEN_SSL_CLIENT.toString())){
			krakenThread.sendCommand(KrakenServerMsg.KRAKEN_SSL_SERVER.makeCommand());
		}
		
		// configuration
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ASK_FOR_CONFIGURATION.toString())) {
			if(msgCmd.length == 3) {
				krakenThread.sendCommand(KrakenServerMsg.SEND_CONFIGURATION.makeCommand(" "+new File(msgCmd[1]).length(), 
						" "+msgCmd[2]));
				FileUtils.tcpSendFile(this.krakenThread.getSocket(), msgCmd[1], "");
			}
		}
		
		//SSL authentification
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ASK_FOR_STREAMING.toString())){
			if(msgCmd.length == 2){
				//TODO récupérer les mdp depuis la BDD ?
				final char[] ksPassword = {'t','o','t','o'};
				final char[] keyPassword = {'t','o','t','o'};
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String ksPath = parser.getValue("AES_KEYSTORE");
				String alias = parser.getValue("AES_ALIAS");
				//TODO charger l'IV depuis quelque part !
				byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			    IvParameterSpec ivspec = new IvParameterSpec(iv);
				
				// Load Key From Keystore
				SecretKey aesKey = AES256.loadKeyFromKeyStore(ksPath, ksPassword, keyPassword, alias);
				Cipher decryptCipher = AES256.initCipherDecrypt(aesKey, ivspec);
				
				byte[] decryptedData = AES256.decrypt(StringUtils.stringToBytes(msgCmd[1]),aesKey,decryptCipher);
				
				Token receivedToken = new Token(decryptedData);
				if(receivedToken.checkToken()){
					System.out.println("Jeton valide !");
					//on instancie le numero de la demande, pour le lien entre commandes et streaming
					//String numDmd = "num";
					this.numDemande = receivedToken.getTokenNumDemande();
					this.getKrakenThread().getKrakenSSLServer().insertCommandIntoMap(this.numDemande, "");
					this.getKrakenThread().getKrakenSSLServer().getStreamingServiceFPSMap().put(this.numDemande, 0);
					
					// si ok, génerer jeton video, le chiffrer et l'envoyer
					//Token token = new Token("YES_TOKEN");
					Token token = new Token(new Integer(receivedToken.getTokenNumDemande()), new Integer(receivedToken.getTokenTypeDemande()), receivedToken.getTokenIPServer(), receivedToken.getTokenIPCam());
					
					Cipher encryptCipher = AES256.initCipherEncrypt(aesKey, ivspec);
					byte[] encryptedData = AES256.encrypt(token.getInformation(),aesKey,encryptCipher);
					
					krakenThread.sendCommand(KrakenServerMsg.SEND_GENERATED_VIDEO_TOKEN.makeCommand( " "+StringUtils.bytesToString(encryptedData)));
				}
				else{
					System.out.println("Jeton non valide");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.ASK_FOR_STREAMING.toString(), " "+KrakenServerMsg.INVALID_TOKEN.toString()));
				}
			}
			else{
				krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.ASK_FOR_STREAMING.toString()));
			}
		}
		
		// start streaming
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.READY_FOR_STREAMING.toString())) {
			if(msgCmd.length == 2) {
				krakenThread.sendCommand(KrakenServerMsg.START_STREAM.makeCommand(" "+msgCmd[1]));
				
				if(msgCmd[1].equals("vid")){
					System.out.println("On fournit le service video!");
					
					ConfParser parser = new ConfParser();
					try {
						parser.parse(new File(AppletConstant.LOCAL_CONF));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					Integer fps = new Integer(parser.getValue("FPS_MAX"));
					threadSendImage = new KrakenSSLThreadSendImage(this, this.camName, this.numDemande, fps);
					
					//on contrôle les commandes
					boolean goOn = true;
					String cmdClient = "";
					
					while(goOn){
						//on verifie la map des commandes
						cmdClient = this.getKrakenThread().getKrakenSSLServer().getStreamingServiceCommandMap().get(this.numDemande);
						
						if(!cmdClient.equals("")){
							//etablir les différentes commandes !
							//System.out.println("COMMANDE:"+cmdClient);
							if(cmdClient.equals(KrakenClientMsg.PAUSE_STREAM.msg)){
								threadSendImage.pauseThreadSendImage();
								this.getKrakenThread().getKrakenSSLServer().getStreamingServiceCommandMap().put(this.numDemande, "");
							}
							else if(cmdClient.equals(KrakenClientMsg.PLAY_STREAM.msg)){
								threadSendImage.goOnThreadSendImage();
								this.getKrakenThread().getKrakenSSLServer().getStreamingServiceCommandMap().put(this.numDemande, "");
							}
							else if(cmdClient.equals(KrakenClientMsg.STOP_STREAM.msg)){
								threadSendImage.stopThreadSendImage();
								this.getKrakenThread().getKrakenSSLServer().getStreamingServiceCommandMap().remove(this.numDemande);
								this.getKrakenThread().getKrakenSSLServer().getStreamingServiceFPSMap().remove(this.numDemande);
								goOn = false;
							}
							else{
								//error
							}
						}
						
						try {
							Thread.sleep(50);
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					krakenThread.setRunOff();
					//krakenThread.sendCommand(KrakenServerMsg.END_STREAM.makeCommand());
				}
			}
		}
		
		// report fps
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.REPORT_FPS.toString())) {
			if(msgCmd.length == 2) {
				this.krakenThread.getKrakenSSLServer().insertFPSIntoMap(this.numDemande, new Integer(msgCmd[1]));
				krakenThread.sendCommand(KrakenServerMsg.FPS_UPDATED.makeCommand());
			}
		}
		
		// stop stream
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.STOP_STREAM.toString())) {
			if(msgCmd.length == 1) {
				this.krakenThread.getKrakenSSLServer().insertCommandIntoMap(this.numDemande, KrakenClientMsg.STOP_STREAM.toString());
				//n'attend pas de réponse
			}
		}
		
		// pause stream
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.PAUSE_STREAM.toString())) {
			if(msgCmd.length == 1) {
				this.krakenThread.getKrakenSSLServer().insertCommandIntoMap(this.numDemande, KrakenClientMsg.PAUSE_STREAM.toString());
				//n'attend pas de réponse
			}
		}
		
		// play stream
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.PLAY_STREAM.toString())) {
			if(msgCmd.length == 1) {
				this.krakenThread.getKrakenSSLServer().insertCommandIntoMap(this.numDemande, KrakenClientMsg.PLAY_STREAM.toString());
				//n'attend pas de réponse
			}
		}
		
		//SSL video streaming
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_TOKEN_FOR_VIDEO.toString())){
			if(msgCmd.length == 2){
				//TODO récupérer les mdp depuis la BDD ?
				final char[] ksPassword = {'t','o','t','o'};
				final char[] keyPassword = {'t','o','t','o'};
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String ksPath = parser.getValue("AES_KEYSTORE");
				String alias = parser.getValue("AES_ALIAS");
				//TODO charger l'IV depuis quelque part !
				byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			    IvParameterSpec ivspec = new IvParameterSpec(iv);
				
				// Load Key From Keystore
				SecretKey aesKey = AES256.loadKeyFromKeyStore(ksPath, ksPassword, keyPassword, alias);
				Cipher decryptCipher = AES256.initCipherDecrypt(aesKey, ivspec);
				
				byte[] decryptedData = AES256.decrypt(StringUtils.stringToBytes(msgCmd[1]),aesKey,decryptCipher);
				
				Token receivedToken = new Token(decryptedData);
				if(receivedToken.checkToken()){
					System.out.println("Jeton valide !");
					//String numDmd = "num";
					this.camName = receivedToken.getTokenIPCam();
					this.numDemande = receivedToken.getTokenNumDemande();
					krakenThread.sendCommand(KrakenServerMsg.VIDEO_SERVICE_AUTHENTIFICATED.makeCommand());
				}
				else{
					System.out.println("Jeton non valide");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.SEND_TOKEN_FOR_VIDEO.toString(), " "+KrakenServerMsg.INVALID_TOKEN.toString()));
				}
			}
			else{
				krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.SEND_TOKEN_FOR_VIDEO.toString()));
			}
		}
		
		//SSL video download
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.toString())){
			if(msgCmd.length == 2){
				//TODO récupérer les mdp depuis la BDD ?
				final char[] ksPassword = {'t','o','t','o'};
				final char[] keyPassword = {'t','o','t','o'};
						
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.STOR_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String ksPath = parser.getValue("AES_KEYSTORE");
				String alias = parser.getValue("AES_ALIAS");
				//TODO charger l'IV depuis quelque part !
				byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
			    IvParameterSpec ivspec = new IvParameterSpec(iv);
				
				// Load Key From Keystore
				SecretKey aesKey = AES256.loadKeyFromKeyStore(ksPath, ksPassword, keyPassword, alias);
				Cipher decryptCipher = AES256.initCipherDecrypt(aesKey, ivspec);
				
				byte[] decryptedData = AES256.decrypt(StringUtils.stringToBytes(msgCmd[1]),aesKey,decryptCipher);
				
				Token receivedToken = new Token(decryptedData);
				if(receivedToken.checkToken()){
					System.out.println("Jeton valide !");
					this.listVideos = receivedToken.getTokenListVideos();
					this.numDemande = receivedToken.getTokenNumDemande();
					if(receivedToken.getTokenTypeDemande().equals("2"))
						this.userName = receivedToken.getTokenUser();
					
					krakenThread.sendCommand(KrakenServerMsg.VIDEO_SERVICE_AUTHENTIFICATED.makeCommand());
				}
				else{
					System.out.println("Jeton non valide");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.toString(), " "+KrakenServerMsg.INVALID_TOKEN.toString()));
				}
			}
			else{
				krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" "+KrakenClientMsg.SEND_TOKEN_FOR_DOWNLOAD.toString()));
			}
		}
		
		// start download
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.READY_FOR_DOWNLOAD.toString())) {
			//videos
			if(msgCmd.length == 3) {
				//1 = chemin où envoyer les vidéos & 2 = user name
				//récupération des vidéos dans la liste sauvées
				ArrayList<String> videos_paths = new ArrayList<String>();
				String[] videos = this.listVideos.split(":");
				String finalPath;
				int nbreFichiers = 0;
				String nomsFichiers = "";
				String poidsFichiers = "";
				String clearVideoPath = "";
				String newEncryptedVideoPath = "";
				String newEncryptedVideoName = "";
				String newKeystoreName = "";
				String newKeystorePath = "";
				Keystore keystore = null;
				Keystore newKeystore = null;
								
				Session session = HibernateUtil.getSession();
				//Transaction tx = session.beginTransaction();
				for(String vid_id : videos){
					Transaction tx = session.beginTransaction();
					Video video = (Video) session.createCriteria(Video.class).
							add(Restrictions.like("video_id", Integer.parseInt(vid_id))).list().get(0);
					finalPath = video.getVideo_path();
					clearVideoPath = finalPath.replaceAll(".encrypt", "");
					for(Keystore keys : video.getKeystore()){
						if(keys.isKey_usedForStorage())	keystore = keys;
					}
					
					//on déchiffre la vidéo
					newKeystorePath = finalPath.substring(0,finalPath.length()-".mp4.encrypt".length())+".keystore";
					//AES256.createAESKeyStore(newKeystorePath, keystore.getKey_password(), keystore.getKey_containedKeyPassword(), keystore.getKey_alias());
					FileUtils.byteArrayToFile(keystore.getKey_keystore(), newKeystorePath);
					AES256.decryptInputFile(finalPath, clearVideoPath, newKeystorePath, keystore.getKey_password(), keystore.getKey_containedKeyPassword(), keystore.getKey_alias(), keystore.getKey_iv());
					new File(newKeystorePath).delete();
					
					//on chiffre la vidéo avec un nouveau keystore !
					newEncryptedVideoPath = video.getVideo_path().replaceAll(".mp4", "_"+msgCmd[2]+".mp4");
					newEncryptedVideoName = video.getVideo_name().replaceAll(".mp4", "_"+msgCmd[2]+".mp4");
					newKeystoreName = video.getVideo_name().replaceAll(".mp4.encrypt", ".keystore");
					//TODO
					List<Keystore> keystoreFromDatabase = session.createCriteria(Keystore.class).
							add(Restrictions.like("key_name", newKeystoreName)).
							add(Restrictions.like("key_user", msgCmd[2])).
							add(Restrictions.like("key_usedForStorage", false)).
							add(Restrictions.like("video", video)).list();
					
					final char[] ksPassword = StringUtils.generateRandomString(16).toCharArray();
					final char[] keyPassword = StringUtils.generateRandomString(16).toCharArray();
					byte[] iv = StringUtils.stringToBytes(StringUtils.generateRandomString(16));
					
					AES256.createAESKeyStore(newKeystorePath, ksPassword, keyPassword, keystore.getKey_alias());
					File keystoreFile = new File(newKeystorePath);
					long weight = keystoreFile.length();
					byte[] keystoreContent = FileUtils.fileToByteArray(keystoreFile, Math_.safeLongToInt(weight));
					
					if(!keystoreFromDatabase.isEmpty()){
						System.out.println("Keystore existant : update!"+keystoreFromDatabase.size());
						keystore = keystoreFromDatabase.get(0);
						video.delKeystore(keystore);
						tx.commit();
						tx = session.beginTransaction();
						newKeystore = new Keystore(newKeystoreName, newKeystorePath, iv, ksPassword, keyPassword, keystore.getKey_alias(), weight, false, msgCmd[2], keystoreContent, video);

					}
					else{
						System.out.println("Keystore inexistant : creation!");
						newKeystore = new Keystore(newKeystoreName, newKeystorePath, iv, ksPassword, keyPassword, keystore.getKey_alias(), weight, false, msgCmd[2], keystoreContent, video);
					}
					video.addKeystore(newKeystore);
					session.save(newKeystore);
					session.save(video);
					tx.commit();
					
					AES256.encryptInputFile(clearVideoPath, newEncryptedVideoPath, newKeystorePath, ksPassword, keyPassword, newKeystore.getKey_alias(), iv);
					new File(newKeystorePath).delete();
					new File(clearVideoPath).delete();
					
					videos_paths.add(newEncryptedVideoPath);
					if(nbreFichiers > 0){
						nomsFichiers += ":";
						poidsFichiers += ":";
					}
					nbreFichiers++;
					nomsFichiers += newEncryptedVideoName;
					poidsFichiers += String.valueOf(video.getVideo_weight());
				}
				//tx.commit();
				session.close();
				
				krakenThread.sendCommand(KrakenServerMsg.START_DOWNLOAD.makeCommand(" video", " "+nbreFichiers, " "+nomsFichiers, " "+poidsFichiers));
				
				//transférer tous les fichiers dans videos_paths
				for(String video_path : videos_paths){
					System.out.println("Transfert de :"+video_path);
					FileUtils.tcpSendFile(this.krakenThread.getSocket(), video_path, msgCmd[1]);
					new File(video_path).delete();
				}
			}
			//clés
			else if(msgCmd.length == 2) {
				//1 = chemin où envoyer les clés
				//récupération des vidéos dans la liste sauvées
				ArrayList<String> keystore_paths = new ArrayList<String>();
				String[] videos = this.listVideos.split(":");
				int nbreFichiers = 0;
				String nomsFichiers = "";
				String poidsFichiers = "";
				String newKeystorePath = "";
				Keystore keystore = null;
								
				Session session = HibernateUtil.getSession();
				Transaction tx = session.beginTransaction();
				
				//pour chaque video, on récupère le keystore créé pour l'utilisateur
				for(String vid_id : videos){
					Video video = (Video) session.createCriteria(Video.class).
							add(Restrictions.like("video_id", Integer.parseInt(vid_id))).list().get(0);
					for(Keystore keys : video.getKeystore()){
						if(!keys.isKey_usedForStorage())	
							if(keys.getKey_user().equals(this.userName))	keystore = keys;
					}
					
					//on recréé le keystore
					newKeystorePath = keystore.getKey_path();
					//AES256.createAESKeyStore(newKeystorePath, keystore.getKey_password(), keystore.getKey_containedKeyPassword(), keystore.getKey_alias());
					FileUtils.byteArrayToFile(keystore.getKey_keystore(), newKeystorePath);
					
					keystore_paths.add(newKeystorePath);
					if(nbreFichiers > 0){
						nomsFichiers += ":";
						poidsFichiers += ":";
					}
					nbreFichiers++;
					nomsFichiers += keystore.getKey_name();
					poidsFichiers += String.valueOf(keystore.getKey_weight());
				}
				tx.commit();
				session.close();
				
				krakenThread.sendCommand(KrakenServerMsg.START_DOWNLOAD.makeCommand(" keystore", " "+nbreFichiers, " "+nomsFichiers, " "+poidsFichiers));
				
				//transférer tous les fichiers dans keystore_paths
				for(String key_path : keystore_paths){
					System.out.println("Transfert de :"+key_path);
					FileUtils.tcpSendFile(this.krakenThread.getSocket(), key_path, msgCmd[1]);
					new File(key_path).delete();
				}
			}
		}
		
		//nettoyage de répertoire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.CLEAN_FOLDER.toString())){
			if(msgCmd.length == 2){
				FileUtils.cleanDirectory(msgCmd[1]);
				krakenThread.sendCommand(KrakenServerMsg.FOLDER_CLEAN.makeCommand());
			}
		}
		
		//création répertoire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.CREATE_DIRECTORY.toString())){
			if(msgCmd.length == 2){
				if(!new File(msgCmd[1]).exists())
		            new File(msgCmd[1]).mkdirs();
				krakenThread.sendCommand(KrakenServerMsg.DIRECTORY_SAVED.makeCommand());
			}
		}
		
		//copie de fichier
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.COPY_FILE.toString())){
			if(msgCmd.length == 4){
				this.savedMessage = msgCmd[0];
				krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1]," "+msgCmd[2]));
				FileUtils.tcpWaitingFileByWeight(krakenThread.getSocket(),msgCmd[2],Long.valueOf(msgCmd[3]));
				krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
			}
			else if(msgCmd.length == 3){
				this.savedMessage = msgCmd[0];
				krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1]," "+msgCmd[2]));
				FileUtils.tcpWaitingFile(krakenThread.getSocket(),msgCmd[2]);
				krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
			}
		}
		
		//fichier envoyé
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.FILE_SENDED.toString())){
			if(savedMessage.equalsIgnoreCase(KrakenClientMsg.COPY_FILE.toString())){
				this.savedMessage = "";
				krakenThread.sendCommand(KrakenServerMsg.FILE_SAVED.makeCommand());
			}
		}
				
		//Initialisation du système de chiffrement modulaire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ENCRYPTION_DISTRIBUTION.toString())){
			if(msgCmd.length == 3){				
				if(msgCmd[1].equalsIgnoreCase("GLOBAL")){
					//récupérer chemin où copier sur serv global dans fichier config
					ConfParser parser = new ConfParser();
					try {
						parser.parse(new File(AppletConstant.GLOBAL_CONF));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					String path = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
					krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_DISTRIBUTION.makeCommand(" GLOBAL"," "+msgCmd[2]," "+path));
				}
				else if(msgCmd[1].equalsIgnoreCase("LOCAL")){
					//récupérer chemin où copier sur serv local dans fichier config
					ConfParser parser = new ConfParser();
					try {
						parser.parse(new File(AppletConstant.LOCAL_CONF));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					String path = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
					krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_DISTRIBUTION.makeCommand(" LOCAL", " "+msgCmd[2], " "+path));
				}
			}
			else if(msgCmd.length == 4){
				if(msgCmd[1].equalsIgnoreCase("LOCAL")){
					//1 = LOCAL & 2 = ip local & 3 = chemin stockage des fichiers copiés sur le global
					//créer un client avec les messages reçus
					
					String answer = "";
					String ip = msgCmd[2];
					ArrayList<String> msg_to_send = new ArrayList<String>();
					msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
					msg_to_send.add(KrakenClientMsg.ENCRYPTION_DISTRIBUTION.makeCommand(" LOCAL"," "+msgCmd[3]));
					msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
							
					KrakenSSLClient krakenClient = new KrakenSSLClient(msg_to_send,ip,0);
					krakenClient.connect();
					krakenClient.communicate();
							
					answer = krakenClient.getFinalAnswer();
					if(answer.equalsIgnoreCase("END_SERVER")){
						System.out.println("Distribution locale des classes réussie");
						krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.makeCommand());
					}
					else{
						System.out.println("Distribution locale des classes failed");
						krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
					}
				}
			}
		}
		
		//Paramétrage du système de chiffrement modulaire
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.ENCRYPTION_PARAMETER.toString())){
			if(msgCmd.length == 4){
				//1 = nom fichier & 2 = ip global & 3 = ip local
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]," "+msgCmd[3]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenSSLClient krakenClient = new KrakenSSLClient(msg_to_send,ip,0);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase("END_SERVER")){
					System.out.println("Paramétrage local de "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
				}
				else{
					System.out.println("Paramétrage local de "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
				//krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
			}
			else if(msgCmd.length == 3){
				//1 = nom fichier & 2 = ip local
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenSSLClient krakenClient = new KrakenSSLClient(msg_to_send,ip,0);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase("END_SERVER")){
					System.out.println("Paramétrage local de "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
				}
				else{
					System.out.println("Paramétrage local de "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
				//krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
			}
			else if(msgCmd.length == 2){
				//1 = nom fichier
				//copier le fichier directement
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				String pathToCopy = parser.getValue("PATH_ENCRYPTION_PARAMETER");
				String pathOfClasses = parser.getValue("PATH_ENCRYPTION_DISTRIBUTION");
				File[] files = FileUtils.listFiles(pathOfClasses);
				String tmp[];
				System.out.println(pathOfClasses);
				
				for(File file : files){
					System.out.println(file.getName());
					tmp = file.getName().split("\\.");
					if(tmp[0].equalsIgnoreCase(msgCmd[1])){
						try {
							FileUtils.cleanDirectory(pathToCopy);
							FileUtils.copyFileBuffered(file.getAbsolutePath(), pathToCopy+file.getName(), 4);
							krakenThread.sendCommand(KrakenServerMsg.END_ENCRYPTION_PARAMETER.makeCommand());
						} catch (FileNotFoundException e) {
							e.printStackTrace();
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				//krakenThread.sendCommand(KrakenServerMsg.PATH_ENCRYPTION_PARAMETER.makeCommand(" "+msgCmd[1]," "+pathOfClasses, " "+pathToCopy));
			}
		}
		
		//generation clé RSA
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.GENERATE_RSA_KEY.toString())){
			//appeler le programme pour génerer clé RSA
			krakenThread.sendCommand(KrakenServerMsg.RSA_KEY_GENERATED.makeCommand());
		}
		
		//generation clé
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.GENERATE_KEY.toString())){
			if(msgCmd.length == 5){
				//servWeb: 1 = algo & 2 = ip global & 3 = ip local & 4 = global name
				String answer = "";
				String ip = msgCmd[2];
				ArrayList<String> msg_to_send = new ArrayList<String>();
				msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msg_to_send.add(KrakenClientMsg.GENERATE_KEY.makeCommand(" "+msgCmd[1], " "+msgCmd[3], " "+msgCmd[4]));
				msg_to_send.add(KrakenClientMsg.END_CLIENT.toString());
						
				KrakenSSLClient krakenClient = new KrakenSSLClient(msg_to_send,ip,0);
				krakenClient.connect();
				krakenClient.communicate();
						
				answer = krakenClient.getFinalAnswer();
				if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
					System.out.println("Génération de clé "+msgCmd[1]+" réussi");
					krakenThread.sendCommand(KrakenServerMsg.KEY_GENERATED.makeCommand());
				}
				else{
					System.out.println("Génération de clé "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
			}
			else if(msgCmd.length == 4){
				//serv global: 1 = algo & 2 = ip local & 3 = global name
				String algo = msgCmd[1];
				String ip = msgCmd[2];
				int out = -10;
				String size;
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.GLOBAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				String keyPath = parser.getValue("ENCRYPTION_KEY");
				String path = keyPath+algo+".key";
				
				if(algo.equalsIgnoreCase("lfsr")){
					size = parser.getValue("LFSR_SIZE");
				}
				else	size = "64";
				
				FileUtils.cleanDirectory(keyPath);
				String[] args = {parser.getValue("CRYPTO_CIPHER"), "-k", algo, path, size}; 
				
				//prog externe
				try {
					ExecuteExternalApplication eea = new ExecuteExternalApplication();
					out = eea.execute(args);
				} catch (IOException e) {
					e.printStackTrace();
				}
				
				if(out == 0){
					String key = KeyParser.parseKey(algo, path);
					if(key == null){
						System.out.println("Mauvais format de clé");
						// ERR
					}
					else{
						Session session = HibernateUtil.getSession();
						Transaction tx = session.beginTransaction();
						ServerSite site = (ServerSite) session.createCriteria(ServerSite.class).
								add(Restrictions.like("siteserv_ip", ip)).list().get(0);
						site.setSiteserv_key(key);
						session.save(site);
						tx.commit();
						session.close();
						
						//envoie au serv local
						try {
							String dh_key = CipherModule.readDHKey(parser.getValue("DH_KEY")+msgCmd[3]+".dh");
							if(!dh_key.equalsIgnoreCase("")){
								String encryptedKeyPath = keyPath+algo+".key_c";
								FileUtils.copyFileBufferedEncryptedDH(keyPath+algo+".key", encryptedKeyPath, 4, dh_key);
								
								//(le serv local dechiffre le fichier arrive)
								String answer = "";
								ArrayList<String> msg_to_send = new ArrayList<String>();
								msg_to_send.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
								msg_to_send.add(KrakenClientMsg.GENERATE_KEY.makeCommand(" "+encryptedKeyPath, " "+msgCmd[3]));
								msg_to_send.add(KrakenClientMsg.END_CLIENT.makeCommand());
								
								KrakenSSLClient krakenClient = new KrakenSSLClient(msg_to_send,ip,0);
								krakenClient.connect();
								krakenClient.communicate();
								
								//on supprime le fichier cle genere
								FileUtils.cleanDirectory(keyPath);
										
								answer = krakenClient.getFinalAnswer();
								if(answer.equalsIgnoreCase(KrakenServerMsg.END_SERVER.toString())){
									System.out.println("Génération de clé "+msgCmd[1]+" réussi");
									krakenThread.sendCommand(KrakenServerMsg.KEY_GENERATED.makeCommand());
								}
								else{
									System.out.println("Génération de clé "+msgCmd[1]+" failed");
									krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
								}
							}
							else	System.out.println("Erreur sur la clé DH");
						} catch (IOException e) {
							e.printStackTrace();
						}
					}
				}
				else{
					System.out.println("Génération de clé "+msgCmd[1]+" failed");
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand( " "+KrakenServerMsg.END_ENCRYPTION_DISTRIBUTION.msg));
				}
			}
			else if(msgCmd.length == 3){
				//serv local
				//1 = chemin fichier cle chiffree sur serv global & 2 = global name
				
				ConfParser parser = new ConfParser();
				try {
					parser.parse(new File(AppletConstant.LOCAL_CONF));
				} catch (IOException e) {
					e.printStackTrace();
				}
				String dh_key;
				try {
					FileUtils.cleanDirectory(parser.getValue("ENCRYPTION_KEY"));
					dh_key = CipherModule.readDHKey(parser.getValue("DH_KEY")+msgCmd[2]+".dh");
					String newKeyFile = msgCmd[1].substring(0, msgCmd[1].length()-2);
					//attend la copie du fichier
					krakenThread.sendCommand(KrakenServerMsg.WAITING_FILE.makeCommand(" "+msgCmd[1], " "+msgCmd[1]));
					FileUtils.tcpWaitingFile(krakenThread.getSocket(),msgCmd[1]);
					
					//une fois le fichier copie, on le dechiffre et supprime le chiffre
					try {
						FileUtils.copyFileBufferedEncryptedDH(msgCmd[1], newKeyFile, 4, dh_key);
						new File(msgCmd[1]).delete();
						this.savedMessage = KrakenClientMsg.COPY_FILE.makeCommand();
						
						//fin d'attente du client
						krakenThread.sendCommand(KrakenServerMsg.END_WAITING_FILE.makeCommand());
					} catch (FileNotFoundException e) {
						e.printStackTrace();
					} catch (IOException e) {
						e.printStackTrace();
					}
					
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			}
		}
		
		//fin de la communication
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.END_SSL_CLIENT.toString())){
			krakenThread.sendCommand(KrakenServerMsg.END_SSL_SERVER.makeCommand());
			krakenThread.setRunOff(); //obligatoire pour arrêter le thread
		}
		
		// protocole diffie-hellman
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.DH_KEY.toString())) {
			// serveur web
			if(msgCmd.length == 4) {
				// créer un nouveau client pour propager une nouvelle clé dh
				ArrayList<String> msgToGlobal = new ArrayList<String>();
				msgToGlobal.add(KrakenClientMsg.KRAKEN_CLIENT.toString());
				msgToGlobal.add(KrakenClientMsg.DH_KEY.makeCommand(" "+msgCmd[2], " "+msgCmd[3]));
				msgToGlobal.add(KrakenClientMsg.END_CLIENT.toString());
				
				KrakenSSLClient krakenClient = new KrakenSSLClient(msgToGlobal, msgCmd[1],0);
				krakenClient.connect();
				krakenClient.communicate();
				
				String answer = krakenClient.getFinalAnswer();
				
				if(answer.equalsIgnoreCase("END_SERVER")) {
					System.out.println("Transfert TCP réussi");
					krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
				}
				else
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" TCP_TRANSFERT_FAILED"));
			}
			// serveur global
			else if(msgCmd.length == 3) {
				// generer PGA
				if(dh == null) {
					System.out.println("génération de P et G");
					dh = new DiffieHellman(4, 1024);
					try {
						dh.gen_P();
						dh.gen_G();
					} catch (InterruptedException e) {
						e.printStackTrace();
						krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" DH_COULD_NOT_CREATE_P_OR_G"));
					}
					System.out.println("P et G générés");
				}
				
				try {
					dh.gen_A();
				} catch (InterruptedException e) {
					e.printStackTrace();
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" DH_COULD_NOT_CREATE_A"));
				}
				
				ArrayList<String> msgToLocal = new ArrayList<String>();
				msgToLocal.add(KrakenClientMsg.KRAKEN_CLIENT.makeCommand());
				msgToLocal.add(KrakenClientMsg.DH_KEY.makeCommand());
				msgToLocal.add(KrakenClientMsg.SEND_P.makeCommand(" "+dh.getP().toString()));
				msgToLocal.add(KrakenClientMsg.SEND_G.makeCommand(" "+dh.getG().toString()));
				msgToLocal.add(KrakenClientMsg.SEND_A.makeCommand(" "+dh.getA().toString(), " "+msgCmd[2]));
				msgToLocal.add(KrakenClientMsg.END_CLIENT.makeCommand());
				
				KrakenSSLClient krakenClient = new KrakenSSLClient(msgToLocal, msgCmd[1],0);
				krakenClient.connect();
				krakenClient.communicate();
				
				String answer = krakenClient.getFinalAnswer();
				
				if(answer.equalsIgnoreCase("END_SERVER"))
					System.out.println("Transfert TCP réussi");
				else
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" TCP_TRANSFERT_FAILED"));
				
				// récupérer B
				dh.setB(krakenClient.getB());
				
				// générer la clé
				System.out.println("clé serveur global "+dh.compute_key(dh.getB()));
				
				// réponse ajoutée
				krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
				
				try {
					ConfParser conf = new ConfParser();
					conf.parse(new File(AppletConstant.GLOBAL_CONF));
					CipherModule.writeDHKey(conf.getValue("DH_KEY")+msgCmd[2]+".dh", dh.getK().toString());
				} catch (IOException e) {
					e.printStackTrace();
					krakenThread.sendCommand(KrakenServerMsg.ERROR.makeCommand(" CONF_CANT_OPEN_FILE"));
				}
			}
			
			// côté serveur local
			else if(msgCmd.length == 1) {
				dh = new DiffieHellman(4, 1024);
				krakenThread.sendCommand(KrakenServerMsg.DH_ACK.makeCommand());
			}
			
			// problème
			else
				krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
		}
		
		// côté serveur local
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_P.toString())) {
			// stocker P (synchroniser?)
			dh.setP(new BigInteger(msgCmd[1]));
			krakenThread.sendCommand(KrakenServerMsg.RECEIVED_P.makeCommand());
		}
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_G.toString())) {
			// stocker G (synchroniser?)
			dh.setG(new BigInteger(msgCmd[1]));
			krakenThread.sendCommand(KrakenServerMsg.RECEIVED_G.makeCommand());
		}
		else if(msgCmd[0].equalsIgnoreCase(KrakenClientMsg.SEND_A.toString())) {
			if(msgCmd.length == 3) {
				// stocker A (synchroniser?)
				dh.setA(new BigInteger(msgCmd[1]));
				
				// générer B
				try {
					dh.gen_B();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
	
				krakenThread.sendCommand(KrakenServerMsg.SEND_B.makeCommand(" "+dh.getB().toString()));
				
				// générer la clé
				System.out.println("clé serveur local "+dh.compute_key(dh.getA()));
				try {
					ConfParser conf = new ConfParser();
					conf.parse(new File(AppletConstant.LOCAL_CONF));
					CipherModule.writeDHKey(conf.getValue("DH_KEY")+msgCmd[2]+".dh", dh.getK().toString());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			else
				krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
		}
		
		//Commande inconnue
		else
			krakenThread.sendCommand(KrakenServerMsg.UNKNOWN_COMMAND.makeCommand(msg));
			
	}

	public KrakenSSLThread getKrakenThread() {	return krakenThread;	}
	//public void setKrakenThread(KrakenSSLThread krakenThread) {	this.krakenThread = krakenThread;	}

	public KrakenSSLThreadSendImage getThreadSendImage() {	return threadSendImage;	}
	//public void setThreadSendImage(KrakenSSLThreadSendImage threadSendImage) {	this.threadSendImage = threadSendImage;	}	
	
}
